package com.linked.pay.pay.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.linked.pay.coupon.bean.po.CouponInfoPO;
import com.linked.pay.coupon.service.ICouponHandleService;
import com.linked.pay.feign.IBaseManageFeign;
import com.linked.pay.feign.IScheduledTasksFeign;
import com.linked.pay.pay.bean.dto.PayLogDTO;
import com.linked.pay.pay.bean.param.ApplyRefundParam;
import com.linked.pay.pay.bean.param.PayingParam;
import com.linked.pay.pay.bean.po.PayInfoPO;
import com.linked.pay.pay.service.IPayHandleService;
import com.linked.pay.pay.service.IPayLogService;
import com.linked.pay.points.bean.param.CheckPointsParam;
import com.linked.pay.points.service.IPointsInfoService;
import com.linked.universal.bean.basemanage.generallog.LinkedGeneralLog;
import com.linked.universal.bean.basemanage.generallog.LinkedProject;
import com.linked.universal.bean.pay.param.WaitingPayCreateParam;
import com.linked.universal.bean.pay.result.PayDetailResult;
import com.linked.universal.common.LinkedPrompt;
import com.linked.universal.common.LinkedResult;
import com.linked.universal.common.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author :dbq
 * @date : 2023/3/2 14:23
 * @description : desc
 */
@RestController
@Slf4j
@RequestMapping("payhandle")
public class PayHandleController {

    private final ObjectMapper mapper;

    private final IPayHandleService payHandleService;

    private final IPayLogService payLogService;

    private final IPointsInfoService pointsInfoService;

    private final ICouponHandleService couponHandleService;

    private final JmsMessagingTemplate messagingTemplate;

    private final IScheduledTasksFeign scheduledTasksFeign;

    private final IBaseManageFeign baseManageFeign;


    public PayHandleController(
            IBaseManageFeign baseManageFeign,
            IScheduledTasksFeign scheduledTasksFeign, ObjectMapper mapper, IPayHandleService payHandleService,
            IPayLogService payLogService, IPointsInfoService pointsInfoService,
            ICouponHandleService couponHandleService, JmsMessagingTemplate messagingTemplate) {
        this.mapper = mapper;
        this.payHandleService = payHandleService;
        this.payLogService = payLogService;
        this.pointsInfoService = pointsInfoService;
        this.couponHandleService = couponHandleService;
        this.messagingTemplate = messagingTemplate;
        this.scheduledTasksFeign = scheduledTasksFeign;
        this.baseManageFeign = baseManageFeign;
    }

    /**
     * 创建待支付订单
     */
    @PostMapping("createWaitingPay")
    LinkedResult createWaitingPay(@RequestBody WaitingPayCreateParam param) throws Exception {

        if (log.isInfoEnabled()) {
            log.info("创建待支付订单接口 入参：{}", mapper.writeValueAsString(param));
        }
        PayInfoPO ret = null;
        try {
            ret = payHandleService.createWaitingPay(param);
        } catch (Exception e) {
            log.error("创建待支付订单接口 异常", e);
            return LinkedResult.Error(LinkedPrompt.ERROR_MESSAGE);
        }

        try {
            payLogService.addPayLog(
                    PayLogDTO.Building()
                            .withPayId(ret.getPayId())
                            .withOrderId(param.getOrderId())
                            .withLogStatus(1)
                            .withMethodValue(mapper.writeValueAsString(param))
                            .withUserId(param.getUserId())
            );
            baseManageFeign.insertListkedLog(
                    LinkedGeneralLog.Builder()
                            .withLogProject(LinkedProject.Linked_Pay)
                            .withLogPosition("/payhandle/createWaitingPay")
                            .withPositionName("创建支付单")
                            .withLogOrder(1)
                            .withMethodParam(mapper.writeValueAsString(param))
                            .withMethodResponse(mapper.writeValueAsString(ret))
                            .withTraceId(ret.getPayId())
            );
        } catch (Exception e) {
            log.error("创建待支付订单接口 加日志异常", e);
        }
        return !StringUtils.isEmpty(ret.getPayId()) ? LinkedResult.Success(ret.getPayId()) : LinkedResult.OK(false,LinkedPrompt.CREATE_FAILURE);
    }

    @PostMapping("paying")
    Result paying(@RequestBody PayingParam param) throws Exception {
        if (log.isInfoEnabled()) {
            log.info("生产-支付订单接口 入参：{}", mapper.writeValueAsString(param));
        }
        try {
            String param_json = mapper.writeValueAsString(param);
//            messagingTemplate.convertAndSend(ActiveMQQueueConfig.PAYING_QUEUE, param_json);
        } catch (Exception e) {
            log.error("生产-支付订单接口 异常", e);
            return Result.error("系统异常，请联系管理员");
        }
        return Result.success();
    }


    /**
     * 消费-支付订单
     */
//    @JmsListener(destination = ActiveMQQueueConfig.PAYING_QUEUE)
    //Result receivePaying(String param_json) throws Exception {
    @PostMapping("receivePaying")
    Result receivePaying(@RequestBody PayingParam param) throws Exception {
        //PayingParam param = mapper.readValue(param_json, PayingParam.class);
        if (log.isInfoEnabled()) {
            log.info("消费-支付订单接口 入参：{}", mapper.writeValueAsString(param));
        }
        /**
         *获取支付单信息
         * */
        PayInfoPO payInfo = null;
        try {
            payInfo = payHandleService.findPayInfo(param.getPayId());
            if (payInfo == null) {
                log.info("支付订单接口 支付id无效");
                return Result.ok(false, "支付id无效！");
            }
        } catch (Exception e) {
            log.error("支付订单接口-查询支付单 异常", e);
            return Result.error("系统异常，请联系管理员");
        }
        double realPay = payInfo.getMoneyAmount();

        /**
         * 优惠券校验
         * */
        if (!StringUtils.isEmpty(param.getCouponId())) {
            CouponInfoPO info = couponHandleService.findCouponInfo(param.getCouponId());
            if (info == null) {
                log.info("支付订单接口 优惠券无法识别");
                return Result.ok(false, "优惠券无法识别！");
            }
            boolean check = couponHandleService.checkUserCoupon(param.getUserId(), param.getCouponId());
            if (!check) {
                log.info("支付订单接口 优惠券无效！");
                return Result.ok(false, "优惠券无效！");
            }
            realPay -= info.getReplaceAmount();
        }

        /**
         * 积分校验
         * */
        if (param.getPointsAmount() != null || param.getPointsAmount() >= 0) {
            CheckPointsParam pointsParam = new CheckPointsParam();
            pointsParam.setUserId(param.getUserId());
            pointsParam.setPoints(param.getPointsAmount());
            boolean check_points = pointsInfoService.checkPoints(pointsParam);
            if (!check_points) {
                log.info("用户积分不够!");
                return Result.ok(false, "用户积分不够！");
            }
            realPay -= param.getPointsAmount() / 10;
        }

        /**
         * 修改支付表
         * */
        boolean ret = false;
        try {
            param.setRealAmount(realPay);
            ret = payHandleService.paying(param);
        } catch (Exception e) {
            log.error("支付订单接口 异常", e);
            return Result.error("系统异常，请联系管理员");
        }

        /**
         * 加日志
         * */
        try {
            payLogService.addPayLog(
                    PayLogDTO.Building()
                            .withPayId(param.getPayId())
                            .withOrderId(payInfo.getOrderId())
                            .withLogStatus(2)
                            .withMethodValue(mapper.writeValueAsString(param))
                            .withUserId(param.getUserId())
            );
            baseManageFeign.insertListkedLog(
                    LinkedGeneralLog.Builder()
                            .withLogProject(LinkedProject.Linked_Pay)
                            .withLogPosition("/payhandle/receivePaying")
                            .withPositionName("支付支付单")
                            .withLogOrder(2)
                            .withMethodParam(mapper.writeValueAsString(param))
                            .withMethodResponse(ret + "")
                            .withTraceId(payInfo.getPayId())
            );
        } catch (Exception e) {
            log.error("支付订单接口 加日志异常", e);
        }
        return ret ? Result.success() : Result.ok(false, "");
    }

    @PostMapping("queryPayDetail")
    LinkedResult queryPayDetail(String payId) {
        if (log.isInfoEnabled()) {
            log.info("查询支付单详情接口 入参：" + payId);
        }
        PayDetailResult data = null;
        try {
            data = payHandleService.queryPayDetail(payId);
        } catch (Exception e) {
            log.error("查询支付单详情接口 异常", e);
            return LinkedResult.Error("系统异常，请联系管理员");
        }
        return data != null ? LinkedResult.Success(data) : LinkedResult.OK(false, "查询失败！");
    }

    /**
     * 取消支付单
     */
    @PostMapping("cancelPayBill")
    Result cancelPayBill(String payId) throws Exception {
        if (log.isInfoEnabled()) {
            log.info("取消支付单接口 入参：" + payId);
        }
        /**
         * 1、查询支付单
         * */
        Integer payStatus = payHandleService.queryPayStatusByPayId(payId);
        if (payStatus != 1) {
            log.info("只有未支付的支付单，才可以取消支付单！");
            return Result.ok(false, "只有未支付的支付单，才可以取消支付单！");
        }
        /**
         * 2、修改支付单，支付状态变为：已取消状态
         * */
        boolean ret = false;
        try {
            ret = payHandleService.cancelPayBill(payId);
        } catch (Exception e) {
            log.error("取消支付单接口 异常", e);
            return Result.error("系统异常，请联系管理员");
        }
        return ret ? Result.success() : Result.ok(false, "取消失败！");
    }

    /**
     * 申请退款
     */
    @PostMapping("applyRefund")
    Result applyRefund(@RequestBody ApplyRefundParam param) throws Exception {
        if (log.isInfoEnabled()) {
            log.info("申请退款接口 入参：{}", mapper.writeValueAsString(param));
        }
        /**
         * 1、判断是否是已经支付的支付单
         * */
        PayInfoPO payInfo = payHandleService.findPayInfo(param.getPayId());
        if (payInfo == null || 2 != payInfo.getPayStatus()) {
            log.info("只有支付的支付单，才可以申请退款！");
            return Result.ok(false, "只有支付的支付单，才可以申请退款！");
        }

        boolean ret = false;
        try {
            ret = payHandleService.applyRefund(payInfo);
        } catch (Exception e) {
            log.error("处理退款异常！", e);
            return Result.error("系统异常，请联系管理员");
        }
        try {
            baseManageFeign.insertListkedLog(
                    LinkedGeneralLog.Builder()
                            .withLogProject(LinkedProject.Linked_Pay)
                            .withLogPosition("/payhandle/applyRefund")
                            .withPositionName("申请退款")
                            .withLogOrder(5)
                            .withMethodStatus(ret + "")
                            .withMethodParam(mapper.writeValueAsString(param))
                            //.withMethodResponse(mapper.writeValueAsString(res))
                            .withTraceId(param.getPayId())
            );
        } catch (Exception e) {
            log.error("添加linked日志 异常！", e);
        }
        return ret ? Result.success() : Result.ok(false, "申请退款失败！");
    }

    /**
     * 接受 推送支付结果 回调
     */
    @PostMapping("receiveSendPaymentResultBack")
    Result receiveSendPaymentResultBack(String payId) throws Exception {
        if (log.isInfoEnabled()) {
            log.info("接收-发送支付结果-回调接口 入参：" + payId);
        }
        LinkedResult res = scheduledTasksFeign.removeInquiryByTraceId("sendpayresult", payId);
        baseManageFeign.insertListkedLog(
                LinkedGeneralLog.Builder()
                        .withLogProject(LinkedProject.Linked_Pay)
                        .withLogPosition("/payhandle/receiveSendPaymentResultBack")
                        .withPositionName("接收-发送支付结果-回调")
                        .withLogOrder(4)
                        .withMethodStatus(res.getCode())
                        .withMethodParam(payId)
                        .withMethodResponse(mapper.writeValueAsString(res))
                        .withTraceId(payId)
        );
        return Result.success();
    }
}
